package metar;

/**
 * Wind
 * @author Michel Metzger, Java-Kurs 2013
 * @version 1.0.0
 *
 */
public class WindMetar implements MetarParamInterface {

	/**
	 * Windrichtung in Winkel ° : N=0, O=90, S=180, W=270
	 */
	private int	direction;
	
	/**
	 * variable Windrichtung von
	 */
	private int varyingDirectionFrom;
	
	/**
	 * variable Windrichtung bis
	 */
	private int varyingDirecionTo;
	
	/**
	 * Die Windrichtung ist unbestimmt (variabel)
	 */
	private boolean variable;
	
	/**
	 * Windstille 
	 */
	private boolean windless;
	
	/**
	 * Geschwindigkeit in Knoten
	 */
	private int speed;

	/**
	 * Geschwindigkeit in Böen in Knoten
	 */
	private int speedGusts;
	
	/**
	 * Originalwert aus der Metar-info
	 */
	private String origParam;

	/**
	 * Konstruktor
	 */
	public WindMetar() {
		direction = 0;
		speed = 0;
		variable = false;
		varyingDirectionFrom = 0;
		varyingDirecionTo = 0;
		origParam = "";
	}

	/**
	 * Liefert die Windrichtung in degrees
	 * @return
	 */
	public int getDirection() {
		return direction;
	}

	/**
	 * Liefert true, wenn die Windrichtung unbestimmt bzw. variabel ist
	 * @return
	 */
	public boolean isVariable() {
		return variable;
	}

	/**
	 * Liefert true, wenn Windstille
	 * @return
	 */
	public boolean isWindless() {
		return windless;
	}

	/**
	 * Liefert die wechselnde Windrichtung "von" in degrees
	 * @return
	 */
	public int getVaryingDirectionFrom() {
		return varyingDirectionFrom;
	}

	/**
	 * Liefert die wechselnde Windrichtung "bis" in degrees
	 * @return
	 */
	public int getVaryingDirectionTo() {
		return varyingDirecionTo;
	}

	/**
	 * Liefert die Windgescheindigkeit in Knoten
	 * @return
	 */
	public int getSpeed() {
		return speed;
	}

	/**
	 * Liefert die Windgeschwindigkeit in Böen in Knoten
	 * @return
	 */
	public int getSpeedGusts() {
		return speedGusts;
	}

	/**
	 * Liefert den original Parameter aus dem MetarInfo
	 * @return
	 */
	public String getOrigParam() {
		return origParam;
	}

	/**
	 * Liefert true, wenn der angegebene Parameter Angaben zum Wind enthält
	 * @param val
	 * @return
	 */
	public static boolean isValid(String val) {
		if (val == null) {
			return false;
		}

		val = val.toUpperCase();
		if (val.compareTo("00000KT") == 0 ||
			val.matches("\\d{5}\\D{2,3}") || 
			val.matches("VBR\\d{2}KT") ||
			val.matches("\\d{5}G\\d{2}\\D{2,3}")) {
			return true;
		}
		
		return false;
	}

	public static boolean isValidVaryingExtension(String val) {
		if (val == null) {
			return false;
		}

		if (val.matches("\\d{3}V\\d{3}")) {
			return true;
		}
		
		return false;
	}

	/**
	 * Holt die Angaben zum Wind aus dem Parameter und ggf. Umrechnungen durch
	 * @return
	 * @throws MetarParseException
	 */
	@Override
	public WindMetar parseParam(String val) throws MetarParseException {
		if (!isValid(val) && !isValidVaryingExtension(val)) {
			throw new MetarParseException("Exception while parsing wind!");
		}
		
		/**
		 * Samples:
		 * 29010KT = Windrichtung bezogen auf rechtweisend Nord (290°, also WNW) und Windgeschwindigkeit (10 kt)
		 * VRB03KT = wechselnde Windrichtung, 3 kt
		 * 29010G30KT = Windrichtung 290°, 10 kt in Böen 30 kt
		 * 310V290 = indicates the wind direction is varying from 310° true (northwest) to 290° true (west-northwest).
		 * 00000KT = Windstille
 		 */
		
		val = val.toUpperCase();

		try {
			if (val.compareTo("00000KT") == 0) {
				origParam = val;
				windless = true;
			} else if (val.matches("\\d{5}\\D{2,3}")) {
				origParam = val;
				direction = Integer.valueOf(val.substring(0, 3));
				speed = getSpeed(val.substring(3, 5), val.substring(5));
			} else if (val.matches("\\d{5}G\\d{2}\\D{2,3}")) {
				origParam = val;
				direction = Integer.valueOf(val.substring(0, 3));
				speed = getSpeed(val.substring(3, 5), val.substring(8));
				speedGusts = getSpeed(val.substring(6, 8), val.substring(8));
			} else if (val.matches("VBR\\d{2}KT")) {
				origParam = val;
				variable = true;
				speed = getSpeed(val.substring(3, 5), val.substring(5));
			} else if (val.matches("\\d{3}V\\d{3}")) {
				varyingDirectionFrom = Integer.valueOf(val.substring(0, 3));
				varyingDirecionTo = Integer.valueOf(val.substring(4, 7));
			}
			
			if (MetarInfo.isDebugMode()) {
				System.out.println("*** Wind.windless=" + windless);
				System.out.println("*** Wind.direction=" + direction + "° = " + windDirectionAsString(direction));
				System.out.println("*** Wind.variable=" + variable);
				System.out.println("*** Wind.varyingDirectionFrom=" + varyingDirectionFrom + "° = " + windDirectionAsString(varyingDirectionFrom));
				System.out.println("*** Wind.varyingDirecionTo=" + varyingDirecionTo + "° = " + windDirectionAsString(varyingDirecionTo));
				System.out.println("*** Wind.speed=" + speed + " KT");
				System.out.println("*** Wind.speedGusts=" + speedGusts + " KT");
			}
			
		} catch (NumberFormatException e) {
			if (MetarInfo.isDebugMode()) {
				e.printStackTrace();
			}
			throw new MetarParseException("Exception while parsing wind!", e);
		}
		
		return this;
	}
	
	/**
	 * Liest die Windgeschwindigkeit aus dem angegebenen Parameter
	 * @param val
	 */
	private int getSpeed(String kt, String unit) {
		int speed = Integer.valueOf(kt);
		if (unit.toUpperCase().compareTo("MPH") == 0) {
			// Umrechnen von MPH in KT:  1 mph = 0.86898374931965 kt
			if (MetarInfo.isDebugMode()) {
				System.out.println("Speed MPH=" + speed);
			}
			return (int)((double)speed * 0.86898374931965);
		} else if (unit.toUpperCase().compareTo("KMH") == 0) {
			// Umrechnen von KMH in KT:  1 kmh-1 = 0.53996146834962 kt
			if (MetarInfo.isDebugMode()) {
				System.out.println("Speed KMH=" + speed);
			}
			return (int)((double)speed * 0.53996146834962); 
		}
		return speed;
	}
	
	/**
	 * Windrichtung von deg in String wandeln 
	 * @param deg
	 * @return
	 */
	public static String windDirectionAsString(int deg) {

//		Quelle: http://www.spaa.at/umrechnung.htm
//		N 		Nord 			0° 	
//		NNO 	Nordnordost 	22,5°
//		NO 		Nordost 		45°
//		ONO 	Ostnordost 		67,5°
//		O 		Ost 			90°
//		OSO 	Ostsüdost 		112,5°
//		SO 		Südost 			135°
//		SSO 	Südsüdost 		157,5°
//		S 		Süd 			180°
//		SSW 	Südsüdwest 		202,5°
//		SW 		Südwest 		225°
//		WSW 	Westsüdwest 	247,5°
//		W 		West 			270°
//		WNW 	Westnordwest 	292,5°
//		NW 		Nordwest 		315°
//		NNW 	Nordnordwest 	337,5°		
		
		if (deg >= 0 && deg <= 11) {
			return "N";
		}
		else if (deg <= 33) {
			return "NNE";
		}
		else if (deg <= 56) {
			return "NE";
		}
		else if (deg <= 79) {
			return "ENE";
		}
		else if (deg <= 101) {
			return "E";
		}
		else if (deg <= 124) {
			return "ESE";
		}
		else if (deg <= 146) {
			return "SE";
		}
		else if (deg <= 169) {
			return "SSE";
		}
		else if (deg <= 191) {
			return "S";
		}
		else if (deg <= 214) {
			return "SSW";
		}
		else if (deg <= 236) {
			return "SW";
		}
		else if (deg <= 259) {
			return "WSW";
		}
		else if (deg <= 281) {
			return "W";
		}
		else if (deg <= 304) {
			return "WNW";
		}
		else if (deg <= 326) {
			return "NW";
		}
		else if (deg <= 349) {
			return "NNW";
		}
		else if (deg <= 360) {
			return "N";
		}
		else {
			return "Unknown";
		}
	}
	
	/**
	 * Wandelt die Angabe von Knoten (KT) nach kmh
	 * @param kt
	 * @return
	 */
	public static int convertKTtoKmh(int kt) {
		
		// Umrechnungsfaktor von KT in KMH: 1 KT = 1.852 kmh 
		return (int)((double)kt * 1.852); 
	}

}
